/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.method.base;

import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.entity.accessor.base.AccessorBase;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.property.NestedAccessorFieldGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityGeneratorContext;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.DynamicPropSetPropertyGenerator;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class AcsCopyGenerator extends ClassMethodGenerator
{

	private final String nodeCode;
	protected String className;
	protected List<MediatePropertyInfo> dataType;
	private EntityGeneratorContext entityGeneratorContext;

	public AcsCopyGenerator(String className, String nodeCode, List<MediatePropertyInfo> dataType, EntityGeneratorContext entityGeneratorContext)
	{
		this.nodeCode = nodeCode;
		this.className = className;
		this.dataType=dataType;
		this.entityGeneratorContext = entityGeneratorContext;
	}

	private static final String MethodName = "copyCore";


	@Override
	protected final String getMethodName(){return MethodName;}

	@Override
	protected TypeInfo getReturnType() {
		return new TypeInfo(void.class.getTypeName());
	}

	@Override
	protected boolean getIsOverride() {
		return true;
	}

	@Override
	protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
		ArrayList<Modifier.ModifierKeyword> list =new ArrayList<Modifier.ModifierKeyword>();
		list.add(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
		return list;
	}

	protected static final String paramAccessor = "accessor";

	@Override
	protected ArrayList<ParameterInfo> getParameterCollection() {
		ArrayList<ParameterInfo> list =new ArrayList<ParameterInfo>();
		ParameterInfo parameterInfo= new ParameterInfo();
		parameterInfo.setParamName(paramAccessor);
		parameterInfo.setParamType(new TypeInfo(AccessorBase.class.getTypeName()));
		list.add(parameterInfo);
		return list;
	}

	@Override
	protected Block buildMethodBody() {
		Block block=ast.newBlock();
		addCastObjectStatement(block);
		addSetPropertiesStatements(block);
		return block;
	}

	private void addCastObjectStatement(Block block) {
		VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
		variableDeclarationFragment.setName(ast.newSimpleName(varResult));

		CastExpression castExpression=ast.newCastExpression();
		castExpression.setType(ast.newSimpleType(ast.newName(className)));
		castExpression.setExpression(ast.newSimpleName(paramAccessor));
		variableDeclarationFragment.setInitializer(castExpression);
//		variableDeclarationFragment.setName(ast.newSimpleName(className));

		VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
		variableDeclarationStatement.setType(ast.newSimpleType(ast.newName(className)));

		block.statements().add(variableDeclarationStatement);
	}

	private void addSetPropertiesStatements(Block block)
	{
		for (MediatePropertyInfo info:dataType)
		{
			IGspCommonField field = info.getElement();
			if(field == null){
				continue;
			}
			if(info.getExtendInfos().containsKey("AssoUdtAtrribute"))
				continue;
			if(isDynamicPropSet(field))
				addDynamicPropSetStatent(info,block);
			else if(isNestedAccessField(field))
				addNestedPropStatement(info,block);

			if(isExtendPro(field))
				addExtendPropertyStatement(field, block);
		}

		addExtendPropertyStatements(block);
	}

	protected void addExtendPropertyStatements(Block block) {

	}

	protected  boolean isExtendPro(IGspCommonField field)
	{
		return false;
	}

	protected  void addExtendPropertyStatement(IGspCommonField field,Block block)
	{}

	private boolean isDynamicPropSet(IGspCommonField field) {
		return field.getObjectType()== GspElementObjectType.DynamicProp;
	}

	private void addDynamicPropSetStatent(MediatePropertyInfo info, Block block) {
		String fieldName =	DynamicPropSetPropertyGenerator.getFieldName(
				(IGspCommonField) info.getElement());

		IfStatement ifStatement=ast.newIfStatement();
		addIfPropertyExpression(ifStatement,fieldName);
		addIfThen(ifStatement,info,fieldName);
		block.statements().add(ifStatement);
	}

	private boolean isNestedAccessField(IGspCommonField field)
	{
		return field.getIsUdt();
	}

	private void addNestedPropStatement(MediatePropertyInfo info, Block block)
	{
		String fieldName =	NestedAccessorFieldGenerator.getFieldName(
				(IGspCommonField) info.getElement());

		IfStatement ifStatement=ast.newIfStatement();
		addIfPropertyExpression(ifStatement,fieldName);
		addIfThen(ifStatement,info,fieldName);
		block.statements().add(ifStatement);
	}

	private void addIfPropertyExpression(IfStatement ifStatement, String fieldName) {
		InfixExpression infixExpression=ast.newInfixExpression();
		infixExpression.setLeftOperand(ast.newSimpleName(fieldName));
		infixExpression.setOperator(InfixExpression.Operator.NOT_EQUALS);
		infixExpression.setRightOperand(ast.newNullLiteral());
		ifStatement.setExpression(infixExpression);
	}

	private void addIfThen(IfStatement ifStatement, MediatePropertyInfo info, String fieldName) {

		Block block=ast.newBlock();
		addIfThenCopyStatement(block,info,fieldName);
		addSetBuffer(block,fieldName);
		ifStatement.setThenStatement(block);
	}

	private void addIfThenCopyStatement(Block block, MediatePropertyInfo info, String fieldName) {
		Assignment assignment=ast.newAssignment();

		QualifiedName qualifiedName=ast.newQualifiedName(ast.newSimpleName(varResult),ast.newSimpleName(fieldName));
		assignment.setLeftHandSide(qualifiedName);
		assignment.setOperator(Assignment.Operator.ASSIGN);


		CastExpression castExpression=ast.newCastExpression();
		castExpression.setType(info.getPropertyType().getType(ast));

		MethodInvocation methodInvocation=ast.newMethodInvocation();
		methodInvocation.setName(ast.newSimpleName("copy"));
		methodInvocation.setExpression(ast.newSimpleName(fieldName));
		castExpression.setExpression(methodInvocation);

		assignment.setRightHandSide(castExpression);

		ExpressionStatement expressionStatement=ast.newExpressionStatement(assignment);
		block.statements().add(expressionStatement);
	}

	private void addSetBuffer(Block block,String fieldName)
	{
		MethodInvocation methodInvocation=ast.newMethodInvocation();
		methodInvocation.setName(ast.newSimpleName("setBelongBuffer"));

		ParenthesizedExpression parenthesizedExpression=ast.newParenthesizedExpression();
		CastExpression castExpression=ast.newCastExpression();
		castExpression.setType(ast.newSimpleType(ast.newName(com.inspur.edp.cef.entity.accessor.dataType.ValueObjAccessor.class.getTypeName())));

		QualifiedName qualifiedName=ast.newQualifiedName(ast.newSimpleName(varResult),ast.newSimpleName(fieldName));
		castExpression.setExpression(qualifiedName);

		parenthesizedExpression.setExpression(castExpression);

		methodInvocation.setExpression(parenthesizedExpression);
		methodInvocation.arguments().add(ast.newSimpleName(varResult));

		block.statements().add(ast.newExpressionStatement(methodInvocation));
	}


	protected static final String varResult = "result";
}
